package com.yuyue.springFramework.note09;

import com.yuyue.springFramework.note09.module1.Module1Config;
import com.yuyue.springFramework.note09.module1.Service1;
import com.yuyue.springFramework.note09.module2.Module2Config;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;
import java.util.Map;

/**
 * 《Spring-9 父子容器》文章代码
 *  文章地址：https://mp.weixin.qq.com/s/FeO1oboZkFrCYS83IW9VSQ
 */
public class Note09Test {
    @Test
    //同一个容器中，相同名称的bean会导致报错，父子容器可以解决此问题
    public void fun1(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(Module1Config.class, Module2Config.class);
        applicationContext.refresh();
    }

    @Test
    //定义父子容器解决bean名称一样的问题
    public void fun2(){
        //定义父容器
        AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext();
        applicationContext1.register(Module1Config.class);
        applicationContext1.refresh();

        //定义子容器
        AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext();
        applicationContext2.register(Module2Config.class);
        //指定父容器
        applicationContext2.setParent(applicationContext1);
        applicationContext2.refresh();

        //getBean可以子容器取父容器bean
        Service1 service1 = applicationContext2.getBean(Service1.class);
        service1.method1();
    }

    @Test
    //并非所有方法都可以获取父容器bean
    public void fun3(){
        //定义父容器
        DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
        //在父容器中定义字符串对象
        parentBeanFactory.registerBeanDefinition("userName",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("鱼跃").
                        getBeanDefinition());
        //定义子容器
        DefaultListableBeanFactory childBeanFactory = new DefaultListableBeanFactory();
        //在子容器中定义字符串对象
        childBeanFactory.registerBeanDefinition("addr",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("飞鸟").
                        getBeanDefinition());
        //指定父容器
        childBeanFactory.setParentBeanFactory(parentBeanFactory);

        /*
         * 调用子容器的getBean方法，获取名称为userName的bean，
         * userName这个bean是在父容器中定义的，而getBean方法是BeanFactory接口中定义的，
         * 支持容器层次查找，所以getBean是可以找到userName这个bean的
         * */
        System.out.println("通过名称获取:" + childBeanFactory.getBean("userName"));
        System.out.println("通过名称获取:" + childBeanFactory.getBean("addr"));
        /*
        * 调用子容器的getBeanNamesForType方法，获取所有String类型的bean名称，
        * 而getBeanNamesForType方法是ListableBeanFactory接口中定义的，
        * 这个接口中方法不支持层次查找，只会在当前容器中查找，所以这个方法只会返回子容器的address*/
        System.out.println("通过类型获取" + Arrays.asList(childBeanFactory.getBeanNamesForType(String.class)));
    }

    @Test
    //使用 BeanFactoryUtils.*Ancestors 解决 ListableBeanFactory 无法进行层次查找问题
    public void fun4(){
        //定义父容器
        DefaultListableBeanFactory parentBeanFactory = new DefaultListableBeanFactory();
        //在父容器中定义字符串对象
        parentBeanFactory.registerBeanDefinition("userName",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("鱼跃").
                        getBeanDefinition());
        //定义子容器
        DefaultListableBeanFactory childBeanFactory = new DefaultListableBeanFactory();
        //在子容器中定义字符串对象
        childBeanFactory.registerBeanDefinition("addr",
                BeanDefinitionBuilder.
                        genericBeanDefinition(String.class).
                        addConstructorArgValue("飞鸟").
                        getBeanDefinition());
        //指定父容器
        childBeanFactory.setParentBeanFactory(parentBeanFactory);

        //获取bean名称列表
        String[] strings = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(childBeanFactory, String.class);
        //获取bean
        Map<String, String> map = BeanFactoryUtils.beansOfTypeIncludingAncestors(childBeanFactory, String.class);

        System.out.println(Arrays.asList(strings));
        System.out.println(Arrays.asList(map));
    }

}
